package com.ts.office;

import com.ts.comm.SysString;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.hwpf.usermodel.Table;
import org.apache.poi.hwpf.usermodel.TableCell;
import org.apache.poi.hwpf.usermodel.TableIterator;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.hwpf.usermodel.TableRow;

import java.io.*;
import java.util.*;

/**
 * word操作工具类
 * Created by xhc on 2017-3-22.
 */
public class SysWord {

    /**
     * 替换Word文档中的首位变参
     **/
    public static final String WordFirstParam = "$";

    /**
     * 替换Word文档中的末位变参
     **/
    public static final String WordLastParam = "$";

    public static final String WordStr = "Word";

    /**
     * 读取word为文本
     * @param bContent
     * @return
     * @throws Exception
     */
    public static String readWord(byte[] bContent) throws Exception {
        StringBuffer sRet = new StringBuffer();
        byte[] head = new byte[8];
        byte[] bHead = new byte[]{-48, -49, 17, -32, -95, -79, 26, -31};
        boolean bFlag = false;
        ByteArrayInputStream bis = null;
        try {
            for (int i = 0; i < head.length; i++) {
                if (bContent[i] != bHead[i]) {
                    bFlag = true;
                    break;
                }
            }
            bis = new ByteArrayInputStream(bContent);
            if (bFlag) {
                XWPFParagraph xph = null;
                XWPFDocument document = new XWPFDocument(bis);
                /** 操作Word段落begin */
                Iterator<XWPFParagraph> it = document.getParagraphsIterator();
                while (it.hasNext()) {
                    xph = it.next();
                    sRet.append(xph.getParagraphText() + "\n");
                }
            } else {
                HWPFDocument document = new HWPFDocument(bis);
                Range bodyRange = document.getRange();
                Paragraph ph = null;
                // 先替换段落
                for (int h = 0; h < bodyRange.numParagraphs(); h++) {
                    ph = bodyRange.getParagraph(h);
                    sRet.append(ph.text());
                }
            }

        } catch (Exception e) {
            throw e;
        }
        return sRet.toString();
    }

    /**
     * 读取word所有内容
     *
     * @param ins
     * @return 返回内容字符串
     * @throws Exception
     */
    public static String readWord(InputStream ins) throws Exception {
        StringBuffer sRet = new StringBuffer();
        byte[] bContent = null;
        ByteArrayOutputStream outs = null;
        byte[] head = new byte[8];
        byte[] bHead = new byte[]{-48, -49, 17, -32, -95, -79, 26, -31};
        boolean bFlag = false;
        ByteArrayInputStream bis = null;
        try {
            if (ins == null) {
                throw new Exception("文件流不存在！");
            }
            outs = new ByteArrayOutputStream();
            bContent = new byte[2048];
            int j = -1;
            while ((j = ins.read(bContent)) != -1) {
                outs.write(bContent, 0, j);
            }
            outs.flush();
            bContent = outs.toByteArray();
            outs.close();

            for (int i = 0; i < head.length; i++) {
                if (bContent[i] != bHead[i]) {
                    bFlag = true;
                    break;
                }
            }
            bis = new ByteArrayInputStream(bContent);
            if (bFlag) {
                XWPFParagraph xph = null;
                XWPFDocument document = new XWPFDocument(bis);
                /** 操作Word段落begin */
                Iterator<XWPFParagraph> it = document.getParagraphsIterator();
                while (it.hasNext()) {
                    xph = it.next();
                    sRet.append(xph.getParagraphText() + "\n");
                }
            } else {
                HWPFDocument document = new HWPFDocument(bis);
                Range bodyRange = document.getRange();
                Paragraph ph = null;
                // 先替换段落
                for (int h = 0; h < bodyRange.numParagraphs(); h++) {
                    ph = bodyRange.getParagraph(h);
                    sRet.append(ph.text());
                }
            }

        } catch (Exception e) {
            throw e;
        } finally {
            outs.close();
        }
        return sRet.toString();
    }

    public static String readWord(String sInputPath) throws Exception {
        String sRet = "";
        FileInputStream fis = null;

        if (SysString.isEmpty(sInputPath)) {
            throw new Exception("文件不存在！");
        }
        fis = new FileInputStream(sInputPath);
        sRet = readWord(fis);

        return sRet;
    }

    /**
     * 方法说明：替换word
     *
     * @param sInputPath  源文件路径+文件名
     * @param sOutputPath 目标文件路径+文件名
     * @param mp          "$RecordNum$", "123456"
     * @throws Exception
     */
    public static void replaceWord(String sInputPath, String sOutputPath, HashMap<String, String> mp) throws Exception {
        ByteArrayOutputStream os = null;
        FileOutputStream fout = null;
        byte[] bContent = null;
        try {
            if (!SysString.isEmpty(sInputPath) && !SysString.isEmpty(sOutputPath)) {
                os = new ByteArrayOutputStream();
                replaceWord(new FileInputStream(sInputPath), mp, os);

                if (os != null) {
                    bContent = os.toByteArray();
                    fout = new FileOutputStream(sOutputPath);
                    fout.write(bContent);
                    fout.flush();
                    fout.close();
                }
                os.close();
            }
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                if (fout != null) {
                    fout.close();
                }
                if (os != null) {
                    os.close();
                }
            } catch (Exception e2) {
            }
        }
    }

    /**
     * 方法说明：替换word
     *
     * @param ins 源文件输入流
     * @param mp  "$RecordNum$", "123456"
     * @param os  目标文件输出流
     * @throws Exception
     */
    public static void replaceWord(InputStream ins, HashMap<String, String> mp, OutputStream os) throws Exception {
        byte[] head = new byte[8];
        byte[] bHead = new byte[]{-48, -49, 17, -32, -95, -79, 26, -31};
        boolean bFlag = false;
        byte[] bContent = null;
        ByteArrayOutputStream outs = null;
        try {
            outs = new ByteArrayOutputStream();
            bContent = new byte[2048];
            int j = -1;
            while ((j = ins.read(bContent)) != -1) {
                outs.write(bContent, 0, j);
            }
            outs.flush();
            bContent = outs.toByteArray();
            outs.close();
            for (int i = 0; i < head.length; i++) {
                if (bContent[i] != bHead[i]) {
                    bFlag = true;
                    break;
                }
            }
            if (bFlag) {
                replaceDocx(new ByteArrayInputStream(bContent), mp, os);
            } else {
                replaceDoc(new ByteArrayInputStream(bContent), mp, os);
            }
            os.flush();
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                if (outs != null) {
                    outs.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 方法说明：操作word2003
     *
     * @param ins
     * @param mp
     * @param os
     * @throws IOException
     */
    private static void replaceDoc(InputStream ins, HashMap<String, String> mp, OutputStream os) throws Exception {
        TableIterator it = null;
        Table table = null;
        TableRow tableRow = null;
        TableCell tableCell = null;
        Paragraph paragraph = null;
        int iNumRow = 0; // 表格行数
        int iNumCell = 0; // 表格每行的单元格数
        int iNumParagraph = 0; // 段落数
        String sValue = "";
        HWPFDocument document = new HWPFDocument(ins);
        Range bodyRange = document.getRange();
        // 循环map替换\r为word中识别的回车符
        for (Map.Entry<String, String> entry : mp.entrySet()) {
            sValue = SysString.toString(entry.getValue()).replace("\r", "\013");
            entry.setValue(sValue);
        }
        // 先替换段落
        for (int h = 0; h < bodyRange.numParagraphs(); h++) {
            paragraph = bodyRange.getParagraph(h);
            replaceParagraph2003(paragraph, mp);
        }
        // 替换表格中的段落
        it = new TableIterator(bodyRange);
        while (it.hasNext()) {
            table = (Table) it.next();
            iNumRow = table.numRows();
            for (int i = 0; i < iNumRow; i++) {
                tableRow = table.getRow(i);
                iNumCell = tableRow.numCells();
                for (int j = 0; j < iNumCell; j++) {
                    tableCell = tableRow.getCell(j);
                    iNumParagraph = tableCell.numParagraphs();
                    for (int k = 0; k < iNumParagraph; k++) {
                        paragraph = tableCell.getParagraph(k);
                        replaceParagraph2003(paragraph, mp);
                    }
                }
            }
        }
        document.write(os);
    }

    /**
     * excel2003 替换
     * @param paragraph
     * @param mp
     * @throws Exception
     */
    private static void replaceParagraph2003(Paragraph paragraph, HashMap<String, String> mp) throws Exception {
        String sValue = "";
        try {
            for (Map.Entry<String, String> entry : mp.entrySet()) {
                sValue = paragraph.text();
                if (sValue.indexOf(WordFirstParam) != -1) {
                    sValue = sValue.replace(entry.getKey(), entry.getValue());
                    paragraph.replaceText(sValue, false);
                }
            }
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 方法说明：操作Word2007，并替换Word2007中关键字
     *
     * @param ins
     * @param mp
     * @param os
     * @throws Exception
     */
    private static void replaceDocx(InputStream ins, HashMap<String, String> mp, OutputStream os) throws Exception {
        XWPFDocument document = null;
        Iterator<XWPFTable> itTable = null;
        XWPFTableRow tableRow = null;
        XWPFTable table = null;
        List<XWPFTableCell> cells = null;
        List<XWPFParagraph> cellParagraphs = null;
        Iterator<XWPFParagraph> itParagraph = null;
        XWPFParagraph paragraph = null;
        int iRowCount = 0;
        try {
            if (ins == null) {
                throw new Exception("模版文件不存在！");
            }
            document = new XWPFDocument(ins);
            /** 操作Word段落begin */
            itParagraph = document.getParagraphsIterator();
            while (itParagraph.hasNext()) {
                paragraph = itParagraph.next();
                // 操作段落
                replaceParagraph2007(paragraph, mp);
            }
            /** 操作Word段落end */

            /** 操作Word表格begin */
            itTable = document.getTablesIterator();
            while (itTable.hasNext()) {
                table = itTable.next();
                iRowCount = table.getNumberOfRows();
                for (int i = 0; i < iRowCount; i++) {
                    tableRow = table.getRow(i);
                    cells = tableRow.getTableCells();
                    for (XWPFTableCell cell : cells) {
                        cellParagraphs = cell.getParagraphs();
                        for (int j = 0; j < cellParagraphs.size(); j++) {
                            paragraph = cellParagraphs.get(j);
                            replaceParagraph2007(paragraph, mp);
                        }
                    }
                }
            }
            /** 操作Word表格end */
            document.write(os);
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 方法说明：word2007替换
     *
     * @param paragraph
     * @param mp
     * @throws Exception
     * @throw
     */
    private static void replaceParagraph2007(XWPFParagraph paragraph, HashMap<String, String> mp) throws Exception {
        List<XWPFRun> runs = null;
        XWPFRun run = null;
        ArrayList<Integer[]> arrSetNull = new ArrayList<Integer[]>();
        ArrayList<Object[]> arrSetValue = new ArrayList<Object[]>();
        Object[] cSetValue = null;
        Integer[] cSetNull = null;
        String[] cArr = null;

        boolean bStarFlag = false;
        boolean bEndFlag = false;

        String sValue = "";
        String sText = "";
        String sTmpStr = "";
        String sCutBegStr = "";
        String sCutLastStr = "";
        String sRunValue = "";
        String sTemp = "";
        int iRunIndex = 0;
        int iBegKeyPos = 0;
        int iEndKeyPos = 0;
        int iFirstPostion = 0;
        try {
            if (paragraph != null) {
                // 获得当前段落的集合
                runs = paragraph.getRuns();
                for (int i = 0; i < runs.size(); i++) {
                    iBegKeyPos = 0;
                    sTmpStr = "";
                    // 获取内容
                    sTmpStr = SysString.toString(((XWPFRun) runs.get(i)).getText(0));
                    // 都未出现$字符时
                    if (!bStarFlag && !bEndFlag) {
                        // 在当前字符串中查找是否有$字符
                        iBegKeyPos = sTmpStr.indexOf(WordFirstParam);
                        if (iBegKeyPos != -1) {
                            // 保留当前段落出现$字符出现的run位置
                            iRunIndex = i;
                            // 保留当前段落中要替换的位置
                            iFirstPostion = ((XWPFRun) runs.get(iRunIndex)).getTextPosition() + 1;
                            // 保留第一次出现$字符前面的字符串
                            sCutBegStr = sTmpStr.substring(0, iBegKeyPos);
                            // 从开始出现$符号往后取到结束
                            sText = sTmpStr.substring(iBegKeyPos);

                            // 在截取后的字符串是否有多个$字符,有的就截取开始$字符到出现第二次$字符串
                            iEndKeyPos = sText.lastIndexOf(WordLastParam);
                            if (iEndKeyPos != -1 && iEndKeyPos != 0) {
                                // 保留第二次出现$字符的后面字符串
                                sCutLastStr = sText.substring(iEndKeyPos + 1);
                                sTemp = sText.substring(0, iEndKeyPos + 1);
                                // 这里截取出来的字符串中若只出现2个$的话设置true,否则需要字符串替换
                                if (SysString.findCount(sTemp, WordFirstParam) > 2) {
                                    for (Map.Entry<String, String> entry : mp.entrySet()) {
                                        sTemp = sTemp.replace(entry.getKey(), entry.getValue());
                                    }
                                    sText = sTemp;
                                    run = runs.get(iRunIndex);
                                    run.setText(sCutBegStr + sText + sCutLastStr, iFirstPostion);
                                    continue;
                                }
                                sText = sTemp;
                                bEndFlag = true;
                            }
                            bStarFlag = true;
                            // 若出现前后两个$字符则直接替换，并走下一个循环
                            if (bStarFlag && bEndFlag) {
                                cSetValue = new Object[5];
                                cSetValue[0] = iRunIndex;
                                cSetValue[1] = iFirstPostion;
                                cSetValue[2] = sCutBegStr;
                                cSetValue[3] = sText;
                                cSetValue[4] = sCutLastStr;
                                arrSetValue.add(cSetValue);
                                // 清空并设置成初始值
                                iRunIndex = -1;
                                iFirstPostion = -1;
                                sCutBegStr = "";
                                sText = "";
                                sCutLastStr = "";
                                bStarFlag = false;
                                bEndFlag = false;
                                continue;
                            }
                        }
                    } else {
                        if (!bEndFlag) {
                            iEndKeyPos = sTmpStr.indexOf(WordLastParam);
                            if (iEndKeyPos != -1) {
                                // 保留$字符的后面字符串
                                sCutLastStr = sTmpStr.substring(iEndKeyPos + 1);
                                // 若出现结尾的符号，从0位截
                                sTmpStr = sTmpStr.substring(0, iEndKeyPos + 1);

                                sText += sTmpStr;

                                cSetValue = new Object[5];
                                cSetValue[0] = iRunIndex;
                                cSetValue[1] = iFirstPostion;
                                cSetValue[2] = sCutBegStr;
                                cSetValue[3] = sText;
                                cSetValue[4] = sCutLastStr;
                                arrSetValue.add(cSetValue);
                                // 清空并设置成初始值
                                iRunIndex = -1;
                                iFirstPostion = -1;
                                sCutBegStr = "";
                                sText = "";
                                sCutLastStr = "";
                                bEndFlag = false;
                                bStarFlag = false;
                            } else {
                                // 继续拼接
                                sText += sTmpStr;
                            }
                            cSetNull = new Integer[2];
                            cSetNull[0] = i;

                            cSetNull[1] = ((XWPFRun) runs.get(i)).getTextPosition() + 1;
                            arrSetNull.add(cSetNull);
                        }
                    }
                }
                for (int i = 0; i < arrSetValue.size(); i++) {
                    cSetValue = arrSetValue.get(i);
                    sText = cSetValue[3].toString();
                    iRunIndex = Integer.parseInt(cSetValue[0].toString());
                    if (mp.get(sText) != null) {
                        // 得到替换的内容
                        sRunValue = mp.get(sText).toString();
                        run = runs.get(iRunIndex);
                        sValue = cSetValue[2].toString() + sRunValue + cSetValue[4].toString();
                        if (sValue.indexOf("\r") != -1) {
                            cArr = sValue.split("\r");
                            run.setText(cArr[0].toString(), Integer.parseInt(cSetValue[1].toString()));
                            for (int j = 1; j < cArr.length; j++) {
                                run.addBreak();
                                run.setText(cArr[j], Integer.parseInt(cSetValue[1].toString()) + j);
                            }
                        } else {
                            run.setText(sValue, Integer.parseInt(cSetValue[1].toString()));
                        }
                        for (int j = 0; j < arrSetNull.size(); j++) {
                            run = null;
                            cSetNull = arrSetNull.get(j);

                            run = runs.get(cSetNull[0]);
                            run.setText(null, cSetNull[1]);
                        }
                    }
                }
            }
        } catch (Exception e) {
            throw e;
        }

    }
}
